package com.qiusuo0226.platform.aspect;

import com.qiusuo0226.platform.annotation.RequestRecord;
import com.qiusuo0226.http.util.HttpServletRequestTool;
import com.qiusuo0226.platform.pojo.po.RequestRecordPO;
import com.qiusuo0226.platform.service.RequestRecordService;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;

/**
 * 接口执行基本信息统计切面逻辑
 * @author qiusuo
 * @date 2023/3/22 9:29
 */
@Slf4j
@Component
@Aspect
@Order(10)
public class RequestRecordAspect {

    @Autowired
    private RequestRecordService requestRecordDoService;


    /**
     * 切入点
     * 匹配使用了InterfaceStatistics注解的方法
     */
    @Pointcut("@annotation(com.qiusuo0226.platform.annotation.RequestRecord)")
    private void pt() {}

    /**
     * 环绕通知
     * @param point
     * @return
     * @throws Throwable
     */
    @Around("pt()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        RequestRecordPO record = new RequestRecordPO();

        // 设置一次请求的基本信息
        HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();
        record.setRequestMethod(HttpServletRequestTool.getMethod(request));
        record.setRequestUrl(HttpServletRequestTool.getRequestURL(request));
        record.setRemoteHost(HttpServletRequestTool.getRemoteHost(request));

        // 获取切入点方法point.getSignature()
        Signature signature = point.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;

        // 获取切入点所在目标对象point.getTarget().getClass()
        Class<?> targetClass = point.getTarget().getClass();
        // 获得切点方法对象，因为方法可能重载，所以要根据参数列表类型，获取到具体的方法。
        Method targetMethod = targetClass.getDeclaredMethod(methodSignature.getName(),methodSignature.getParameterTypes());

        // 获取 接口统计注解 对象
        RequestRecord interfaceStatistics = targetMethod.getAnnotation(RequestRecord.class);
        // 是否统计映射地址
        if (interfaceStatistics.mapAddress()) {
            // 类上映射注解
//            String[] mappings = new String[0];
//            if (targetClass.isAnnotationPresent(RequestMapping.class)) {
//                RequestMapping annotation = targetClass.getAnnotation(RequestMapping.class);
//                mappings = annotation.value();
//            }
            // 方法上映射注解
//            String[] path = getPath(targetMethod);
        }

        // 切点方法路径（代码中路径）
        record.setMethodPath(targetClass.getName() + "." + point.getSignature().getName());

        // 接口执行开始时间
        long beginTime = System.currentTimeMillis();

        // 执行切点方法，万一原方法存在异常，也从此处抛出
        Object res = point.proceed();

        // 接口执行耗时
        record.setTimeConsume(System.currentTimeMillis() - beginTime);

        // 接口调用记录
        requestRecordDoService.insertRecord(record);

        log.debug("接口调用统计：{}", record.toString());
        return res;
    }



    /**
     * 获取方法上的Mapping类型的注解值
     * @param method 方法反射对象
     * @return 注解值
     */
    private String[] getPath(Method method) {
        //得到value数组
        String[] value = new String[0];
        // 判断是否存在RequestMapping注解
        if (method.isAnnotationPresent(RequestMapping.class)) {
            // 获取注解对象
            RequestMapping annotation = method.getAnnotation(RequestMapping.class);
            // 获取注解下的value属性的值
            value = annotation.value();
        }
        if (method.isAnnotationPresent(GetMapping.class)) {
            GetMapping annotation = method.getAnnotation(GetMapping.class);
            value = annotation.value();

        }
        if (method.isAnnotationPresent(PostMapping.class)) {
            PostMapping annotation = method.getAnnotation(PostMapping.class);
            value = annotation.value();
        }
        if (method.isAnnotationPresent(PutMapping.class)) {
            PutMapping annotation = method.getAnnotation(PutMapping.class);
            value = annotation.value();
        }
        if (method.isAnnotationPresent(DeleteMapping.class)) {
            DeleteMapping annotation = method.getAnnotation(DeleteMapping.class);
            value = annotation.value();
        }

        for (int i = 0; i < value.length; i++) {
            String s = value[i];
            if (!s.startsWith("/")) {
                value[i] = "/" + s;
            }
        }
        return value;
    }
}
